Lets us read the file.

library(readr)
lyrics <- read_csv("songdata.csv")
Parsed with column specification:
cols(
  artist = col_character(),
  song = col_character(),
  link = col_character(),
  text = col_character()
)
head(lyrics)

Lets us examine the dimension of the lyrics dataframe.

dim(lyrics)
[1] 57650     4
library(dplyr)

Attaching package: 'dplyr'

The following objects are masked from 'package:stats':

    filter, lag

The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
glimpse(lyrics)
Observations: 57,650
Variables: 4
$ artist <chr> "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "ABBA", "AB...
$ song   <chr> "Ahe's My Kind Of Girl", "Andante, Andante", "As Good As New", "Bang", "Bang-A-Boomerang", "Burning...
$ link   <chr> "/a/abba/ahes+my+kind+of+girl_20598417.html", "/a/abba/andante+andante_20002708.html", "/a/abba/as+...
$ text   <chr> "Look at her face, it's a wonderful face  \nAnd it means something special to me  \nLook at the way...

Analysis of 55000+ lyrics data - Number of artists - Which artist has highest and lowest number of songs - Distribution of songs of all artists in the dataset - Distribution of lyrics length - Which song lyrics has maximum number of words - Which song lyrics has minimum number of words - Distribution of words count in title - Which songs title has maximum number of words - Which songs title has minimum number of words - WordClouds of titles with minimum and maximum lengths - Is there a relation between title length and song length?

Let’s start with finding out how many artists are listed in the data. Also, how many songs each artist has.

artist<- as.data.frame(table(as.data.frame(lyrics$artist)))
colnames(artist) <- c("artist", "Num_of_songs")
head(artist)

Let’s see the which artist has most and least number of songs in the dataset.

most_songs <- arrange(artist, desc(Num_of_songs))
most_songs

least_songs <- tail(most_songs, 15)
p2 <- ggplot(data = least_songs, aes(artist, Num_of_songs, fill = Num_of_songs)) +
      geom_bar(stat = "identity") +
      geom_text(aes(label=Num_of_songs), vjust=1.6, color="white", size=3) +
      ggtitle("Artists with least number of songs") +
      tilt_theme
p2

Let’s check the distribution of songs for all artists.

p5 <- ggplot(artist, aes(x=Num_of_songs)) + 
 geom_histogram(aes(y=..density..), colour="black", fill="white")+
 geom_density(alpha=.2, fill="red")
p5

Let’s analyze the number of words in each song and its distribution.

library(stringr)
count_words <- function(vec){
  return (length(unlist((str_extract_all(tolower(vec), '\\w+')))))
}
lyrics$word_count <- sapply(lyrics$text, count_words)
head(lyrics$word_count)
[1] 161 272 322 257 255 115
p4 <- ggplot(lyrics, aes(x=word_count)) + 
 geom_histogram(aes(y=..density..), colour="black", fill="white")+
 geom_density(alpha=.2, fill="red")
p4

Let’s check out the songs that are longest and shortest.

longest_song <- arrange(lyrics, desc(word_count))
longest_song <- head(longest_song, 10)
shortest_song <- arrange(lyrics, word_count)
shortest_song <- head(shortest_song, 10)
longest_song
shortest_song
p5 <- ggplot(data = longest_song, aes(song, word_count, fill = title_word_count)) +
      geom_bar(stat = "identity") +
      geom_text(aes(label=title_word_count), vjust=1.6, color="white", size=3) +
      ggtitle("Longest Songs") +
      tilt_theme
p6 <- ggplot(data = shortest_song, aes(song, word_count, fill = title_word_count)) +
      geom_bar(position = "dodge", stat = "identity") +
      geom_text(aes(label = title_word_count), vjust = 1.6, color = "white", size = 3) +
      ggtitle("Shortest Songs") +
      tilt_theme
multiplot(p5, p6, cols=2)

Let’s analyze the title of the songs, their wordcount and their distribution

lyrics$title_word_count <- sapply(lyrics$song, count_words)
head(lyrics$title_word_count)
[1] 6 2 4 1 3 3
p5 <- ggplot(lyrics, aes(x=title_word_count)) + 
 geom_histogram(aes(y=..density..), colour="black", fill="white", binwidth = 1, bins = 1)+
 geom_density(alpha=.2, fill="red")
p5

WordCloud of popular words from song titles

library(wordcloud)
Loading required package: RColorBrewer
library(SnowballC)
library(RColorBrewer)
library(tm)
Loading required package: NLP

Attaching package: 'NLP'

The following object is masked from 'package:ggplot2':

    annotate
texts <- lyrics$song
#texts <- iconv(texts, to = "utf-8")
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeWords, stopwords('english'))
corpus <- tm_map(corpus, stemDocument)
corpus <- tm_map(corpus, removeWords, c("and", "this", "there")) 
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
d <- d[-which(d$word %in% c("and","this","that")),]
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,
          max.words=200, random.order=FALSE, rot.per=0.35, 
          colors=brewer.pal(8, "Dark2"))

There are many song titles that are of length 1, 2 and 3. But surprisingly, there are titles of length more than 13 too. Let’s check them out.

longest_title <- subset(lyrics, lyrics$title_word_count > 13)
longest_title
shortest_title <- subset(lyrics, lyrics$title_word_count == 1)
shortest_title

There are 8 songs with title length more than 13 and 8342 songs with single word title. Let’s see word cloud of single word titles and longest titles

texts <- longest_title$song
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,scale=c(2,0.5),
          max.words=100, random.order=FALSE, rot.per=0.35, 
          colors=brewer.pal(8, "Dark2"))

texts <- shortest_title$song
corpus <- Corpus(VectorSource(texts))
corpus <- tm_map(corpus, PlainTextDocument)
corpus <- Corpus(VectorSource(corpus))
dtm <- TermDocumentMatrix(corpus)
m <- as.matrix(dtm)
v <- sort(rowSums(m),decreasing=TRUE)
d <- data.frame(word = names(v),freq=v)
head(d, 10)
set.seed(1234)
wordcloud(words = d$word, freq = d$freq, min.freq = 1,scale=c(2,0.5),
          max.words=100, random.order=FALSE, rot.per=0.35, 
          colors=brewer.pal(8, "Dark2"))

An interesting questin would be is there relation between length of title and songs? Most probably now, but let’s check out.

p8 <- ggplot(lyrics, aes(x=factor(title_word_count), y=word_count, fill = factor(title_word_count))) + 
  geom_boxplot() #+
 # geom_jitter(shape=16, position=position_jitter(0.2)) 
p8 

cor(lyrics$title_word_count, lyrics$word_count)
[1] -0.02509779

As expected, there is no correlatin between these two quantitites.

LS0tCnRpdGxlOiAiTHlyaWNzIEFuYWx5c2lzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpMZXRzIHVzIHJlYWQgdGhlIGZpbGUuCgpgYGB7cn0KbGlicmFyeShyZWFkcikKbHlyaWNzIDwtIHJlYWRfY3N2KCJzb25nZGF0YS5jc3YiKQpoZWFkKGx5cmljcykKYGBgCgpMZXRzIHVzIGV4YW1pbmUgdGhlIGRpbWVuc2lvbiBvZiB0aGUgbHlyaWNzIGRhdGFmcmFtZS4KCmBgYHtyfQpkaW0obHlyaWNzKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpnbGltcHNlKGx5cmljcykKYGBgCgpBbmFseXNpcyBvZiA1NTAwMCsgbHlyaWNzIGRhdGEKLSBOdW1iZXIgb2YgYXJ0aXN0cwotIFdoaWNoIGFydGlzdCBoYXMgaGlnaGVzdCBhbmQgbG93ZXN0IG51bWJlciBvZiBzb25ncyAKLSBEaXN0cmlidXRpb24gb2Ygc29uZ3Mgb2YgYWxsIGFydGlzdHMgaW4gdGhlIGRhdGFzZXQKLSBEaXN0cmlidXRpb24gb2YgbHlyaWNzIGxlbmd0aAotIFdoaWNoIHNvbmcgbHlyaWNzIGhhcyBtYXhpbXVtIG51bWJlciBvZiB3b3JkcwotIFdoaWNoIHNvbmcgbHlyaWNzIGhhcyBtaW5pbXVtIG51bWJlciBvZiB3b3JkcwotIERpc3RyaWJ1dGlvbiBvZiB3b3JkcyBjb3VudCBpbiB0aXRsZQotIFdoaWNoIHNvbmdzIHRpdGxlIGhhcyBtYXhpbXVtIG51bWJlciBvZiB3b3JkcyAKLSBXaGljaCBzb25ncyB0aXRsZSBoYXMgbWluaW11bSBudW1iZXIgb2Ygd29yZHMKLSBXb3JkQ2xvdWRzIG9mIHRpdGxlcyB3aXRoIG1pbmltdW0gYW5kIG1heGltdW0gbGVuZ3RocwotIElzIHRoZXJlIGEgcmVsYXRpb24gYmV0d2VlbiB0aXRsZSBsZW5ndGggYW5kIHNvbmcgbGVuZ3RoPwoKCi0gU2VudGltZW50cyBvZiB0aGUgc29uZ3MgKE5SQywgQmluZykKLSBXaGljaCB3b3JkcyBhcmUgbW9zdCBvY2N1cmluZyBpbiB0aGUgbHlyaWNzIG9mIHRoZSBzb25ncwotIElzIHRoZXJlIGEgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgd29yZHMgaW4gdGhlIHNvbmdzIG9mIHNhbWUgYXJ0aXN0cz8KLSBXb3JkY2xvdWQgb2YgbW9zdCBwb3B1bGFyIHdvcmRzIGluIHRoZSBzb25ncwotIFRvcCB3b3JkcyB1c2VkIGJ5IGFuIGFydGlzdCBpbiBoaXMvaGVyIHNvbmdzCi0gQXJlIHRoZXJlIHNvbWUgY29tbW9uIFJ5dGhtaWMgd29yZHMgdGhhdCByZXBlYXRzIGFnYWluIGFuZCBhZ2Fpbj8KCgpMZXQncyBzdGFydCB3aXRoIGZpbmRpbmcgb3V0IGhvdyBtYW55IGFydGlzdHMgYXJlIGxpc3RlZCBpbiB0aGUgZGF0YS4gQWxzbywgaG93IG1hbnkgc29uZ3MgZWFjaCBhcnRpc3QgaGFzLgoKYGBge3J9CmFydGlzdDwtIGFzLmRhdGEuZnJhbWUodGFibGUoYXMuZGF0YS5mcmFtZShseXJpY3MkYXJ0aXN0KSkpCmNvbG5hbWVzKGFydGlzdCkgPC0gYygiYXJ0aXN0IiwgIk51bV9vZl9zb25ncyIpCmhlYWQoYXJ0aXN0KQpgYGAKCkxldCdzIHNlZSB0aGUgd2hpY2ggYXJ0aXN0IGhhcyBtb3N0IGFuZCBsZWFzdCBudW1iZXIgb2Ygc29uZ3MgaW4gdGhlIGRhdGFzZXQuCgpgYGB7cn0KbW9zdF9zb25ncyA8LSBhcnJhbmdlKGFydGlzdCwgZGVzYyhOdW1fb2Zfc29uZ3MpKQptb3N0X3NvbmdzCmBgYAoKYGBge3IgZmlnLndpZHRoPTUsIGZpZy5oZWlnaHQ9MywgZWNobz1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KFJtaXNjKQp0aWx0X3RoZW1lIDwtIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpCnAxIDwtIGdncGxvdChkYXRhID0gaGVhZChtb3N0X3NvbmdzLDEwKSwgYWVzKGFydGlzdCwgTnVtX29mX3NvbmdzLCBmaWxsID0gTnVtX29mX3NvbmdzKSkgKwogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsPU51bV9vZl9zb25ncyksIHZqdXN0PTEuNiwgY29sb3I9IndoaXRlIiwgc2l6ZT0zKSArCiAgICAgIGdndGl0bGUoIkFydGlzdHMgd2l0aCBtb3N0IG51bWJlciBvZiBzb25ncyIpICsKICAgICAgdGlsdF90aGVtZQpwMQpgYGAKCmBgYHtyfQpsZWFzdF9zb25ncyA8LSB0YWlsKG1vc3Rfc29uZ3MsIDE1KQpwMiA8LSBnZ3Bsb3QoZGF0YSA9IGxlYXN0X3NvbmdzLCBhZXMoYXJ0aXN0LCBOdW1fb2Zfc29uZ3MsIGZpbGwgPSBOdW1fb2Zfc29uZ3MpKSArCiAgICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgIGdlb21fdGV4dChhZXMobGFiZWw9TnVtX29mX3NvbmdzKSwgdmp1c3Q9MS42LCBjb2xvcj0id2hpdGUiLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiQXJ0aXN0cyB3aXRoIGxlYXN0IG51bWJlciBvZiBzb25ncyIpICsKICAgICAgdGlsdF90aGVtZQpwMgpgYGAKCkxldCdzIGNoZWNrIHRoZSBkaXN0cmlidXRpb24gb2Ygc29uZ3MgZm9yIGFsbCBhcnRpc3RzLgoKYGBge3J9CnAzIDwtIGdncGxvdChhcnRpc3QsIGFlcyh4PU51bV9vZl9zb25ncykpICsgCiBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiksIGNvbG91cj0iYmxhY2siLCBmaWxsPSJ3aGl0ZSIpKwogZ2VvbV9kZW5zaXR5KGFscGhhPS4yLCBmaWxsPSJyZWQiKQpwMwpgYGAKCkxldCdzIGFuYWx5emUgdGhlIG51bWJlciBvZiB3b3JkcyBpbiBlYWNoIHNvbmcgYW5kIGl0cyBkaXN0cmlidXRpb24uCgpgYGB7cn0KbGlicmFyeShzdHJpbmdyKQpjb3VudF93b3JkcyA8LSBmdW5jdGlvbih2ZWMpewogIHJldHVybiAobGVuZ3RoKHVubGlzdCgoc3RyX2V4dHJhY3RfYWxsKHRvbG93ZXIodmVjKSwgJ1xcdysnKSkpKSkKfQpseXJpY3Mkd29yZF9jb3VudCA8LSBzYXBwbHkobHlyaWNzJHRleHQsIGNvdW50X3dvcmRzKQpoZWFkKGx5cmljcyR3b3JkX2NvdW50KQpgYGAKCmBgYHtyfQpwNCA8LSBnZ3Bsb3QobHlyaWNzLCBhZXMoeD13b3JkX2NvdW50KSkgKyAKIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uKSwgY29sb3VyPSJibGFjayIsIGZpbGw9IndoaXRlIikrCiBnZW9tX2RlbnNpdHkoYWxwaGE9LjIsIGZpbGw9InJlZCIpCnA0CmBgYAoKTGV0J3MgY2hlY2sgb3V0IHRoZSBzb25ncyB0aGF0IGFyZSBsb25nZXN0IGFuZCBzaG9ydGVzdC4KCmBgYHtyfQpsb25nZXN0X3NvbmcgPC0gYXJyYW5nZShseXJpY3MsIGRlc2Mod29yZF9jb3VudCkpCmxvbmdlc3Rfc29uZyA8LSBoZWFkKGxvbmdlc3Rfc29uZywgMTApCnNob3J0ZXN0X3NvbmcgPC0gYXJyYW5nZShseXJpY3MsIHdvcmRfY291bnQpCnNob3J0ZXN0X3NvbmcgPC0gaGVhZChzaG9ydGVzdF9zb25nLCAxMCkKbG9uZ2VzdF9zb25nCnNob3J0ZXN0X3NvbmcKYGBgCgpgYGB7cn0KcDUgPC0gZ2dwbG90KGRhdGEgPSBsb25nZXN0X3NvbmcsIGFlcyhzb25nLCB3b3JkX2NvdW50LCBmaWxsID0gdGl0bGVfd29yZF9jb3VudCkpICsKICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgZ2VvbV90ZXh0KGFlcyhsYWJlbD10aXRsZV93b3JkX2NvdW50KSwgdmp1c3Q9MS42LCBjb2xvcj0id2hpdGUiLCBzaXplPTMpICsKICAgICAgZ2d0aXRsZSgiTG9uZ2VzdCBTb25ncyIpICsKICAgICAgdGlsdF90aGVtZQpwNiA8LSBnZ3Bsb3QoZGF0YSA9IHNob3J0ZXN0X3NvbmcsIGFlcyhzb25nLCB3b3JkX2NvdW50LCBmaWxsID0gdGl0bGVfd29yZF9jb3VudCkpICsKICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKwogICAgICBnZW9tX3RleHQoYWVzKGxhYmVsID0gdGl0bGVfd29yZF9jb3VudCksIHZqdXN0ID0gMS42LCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSAzKSArCiAgICAgIGdndGl0bGUoIlNob3J0ZXN0IFNvbmdzIikgKwogICAgICB0aWx0X3RoZW1lCm11bHRpcGxvdChwNSwgcDYsIGNvbHM9MikKYGBgCgoKTGV0J3MgYW5hbHl6ZSB0aGUgdGl0bGUgb2YgdGhlIHNvbmdzLCB0aGVpciB3b3JkY291bnQgYW5kIHRoZWlyIGRpc3RyaWJ1dGlvbgoKYGBge3J9Cmx5cmljcyR0aXRsZV93b3JkX2NvdW50IDwtIHNhcHBseShseXJpY3Mkc29uZywgY291bnRfd29yZHMpCmhlYWQobHlyaWNzJHRpdGxlX3dvcmRfY291bnQpCmBgYAoKYGBge3J9CnA3IDwtIGdncGxvdChseXJpY3MsIGFlcyh4PXRpdGxlX3dvcmRfY291bnQpKSArIAogZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4pLCBjb2xvdXI9ImJsYWNrIiwgZmlsbD0id2hpdGUiLCBiaW53aWR0aCA9IDEsIGJpbnMgPSAxKSsKIGdlb21fZGVuc2l0eShhbHBoYT0uMiwgZmlsbD0icmVkIikKcDcKYGBgCgpXb3JkQ2xvdWQgb2YgcG9wdWxhciB3b3JkcyBmcm9tIHNvbmcgdGl0bGVzCgpgYGB7cn0KbGlicmFyeSh3b3JkY2xvdWQpCmxpYnJhcnkoU25vd2JhbGxDKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeSh0bSkKdGV4dHMgPC0gbHlyaWNzJHNvbmcKI3RleHRzIDwtIGljb252KHRleHRzLCB0byA9ICJ1dGYtOCIpCmNvcnB1cyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKHRleHRzKSkKY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIFBsYWluVGV4dERvY3VtZW50KQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlUHVuY3R1YXRpb24pCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVXb3Jkcywgc3RvcHdvcmRzKCdlbmdsaXNoJykpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBzdGVtRG9jdW1lbnQpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVXb3JkcywgYygiYW5kIiwgInRoaXMiLCAidGhlcmUiKSkgCmNvcnB1cyA8LSBDb3JwdXMoVmVjdG9yU291cmNlKGNvcnB1cykpCmR0bSA8LSBUZXJtRG9jdW1lbnRNYXRyaXgoY29ycHVzKQptIDwtIGFzLm1hdHJpeChkdG0pCnYgPC0gc29ydChyb3dTdW1zKG0pLGRlY3JlYXNpbmc9VFJVRSkKZCA8LSBkYXRhLmZyYW1lKHdvcmQgPSBuYW1lcyh2KSxmcmVxPXYpCmhlYWQoZCwgMTApCmQgPC0gZFstd2hpY2goZCR3b3JkICVpbiUgYygiYW5kIiwidGhpcyIsInRoYXQiKSksXQpzZXQuc2VlZCgxMjM0KQp3b3JkY2xvdWQod29yZHMgPSBkJHdvcmQsIGZyZXEgPSBkJGZyZXEsIG1pbi5mcmVxID0gMSwKICAgICAgICAgIG1heC53b3Jkcz0yMDAsIHJhbmRvbS5vcmRlcj1GQUxTRSwgcm90LnBlcj0wLjM1LCAKICAgICAgICAgIGNvbG9ycz1icmV3ZXIucGFsKDgsICJEYXJrMiIpKQpgYGAKClRoZXJlIGFyZSBtYW55IHNvbmcgdGl0bGVzIHRoYXQgYXJlIG9mIGxlbmd0aCAxLCAyIGFuZCAzLiBCdXQgc3VycHJpc2luZ2x5LCB0aGVyZSBhcmUgdGl0bGVzIG9mIGxlbmd0aCBtb3JlIHRoYW4gMTMgdG9vLiBMZXQncyBjaGVjayB0aGVtIG91dC4KCmBgYHtyfQpsb25nZXN0X3RpdGxlIDwtIHN1YnNldChseXJpY3MsIGx5cmljcyR0aXRsZV93b3JkX2NvdW50ID4gMTMpCmxvbmdlc3RfdGl0bGUKc2hvcnRlc3RfdGl0bGUgPC0gc3Vic2V0KGx5cmljcywgbHlyaWNzJHRpdGxlX3dvcmRfY291bnQgPT0gMSkKc2hvcnRlc3RfdGl0bGUKYGBgCgpUaGVyZSBhcmUgOCBzb25ncyB3aXRoIHRpdGxlIGxlbmd0aCBtb3JlIHRoYW4gMTMgYW5kIDgzNDIgc29uZ3Mgd2l0aCBzaW5nbGUgd29yZCB0aXRsZS4gTGV0J3Mgc2VlIHdvcmQgY2xvdWQgb2Ygc2luZ2xlIHdvcmQgdGl0bGVzIGFuZCBsb25nZXN0IHRpdGxlcwoKYGBge3J9CnRleHRzIDwtIGxvbmdlc3RfdGl0bGUkc29uZwpjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0cykpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBQbGFpblRleHREb2N1bWVudCkKY29ycHVzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UoY29ycHVzKSkKZHRtIDwtIFRlcm1Eb2N1bWVudE1hdHJpeChjb3JwdXMpCm0gPC0gYXMubWF0cml4KGR0bSkKdiA8LSBzb3J0KHJvd1N1bXMobSksZGVjcmVhc2luZz1UUlVFKQpkIDwtIGRhdGEuZnJhbWUod29yZCA9IG5hbWVzKHYpLGZyZXE9dikKaGVhZChkLCAxMCkKc2V0LnNlZWQoMTIzNCkKd29yZGNsb3VkKHdvcmRzID0gZCR3b3JkLCBmcmVxID0gZCRmcmVxLCBtaW4uZnJlcSA9IDEsc2NhbGU9YygyLDAuNSksCiAgICAgICAgICBtYXgud29yZHM9MTAwLCByYW5kb20ub3JkZXI9RkFMU0UsIHJvdC5wZXI9MC4zNSwgCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg4LCAiRGFyazIiKSkKYGBgCgpgYGB7cn0KdGV4dHMgPC0gc2hvcnRlc3RfdGl0bGUkc29uZwpjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0cykpCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCBQbGFpblRleHREb2N1bWVudCkKY29ycHVzIDwtIENvcnB1cyhWZWN0b3JTb3VyY2UoY29ycHVzKSkKZHRtIDwtIFRlcm1Eb2N1bWVudE1hdHJpeChjb3JwdXMpCm0gPC0gYXMubWF0cml4KGR0bSkKdiA8LSBzb3J0KHJvd1N1bXMobSksZGVjcmVhc2luZz1UUlVFKQpkIDwtIGRhdGEuZnJhbWUod29yZCA9IG5hbWVzKHYpLGZyZXE9dikKaGVhZChkLCAxMCkKc2V0LnNlZWQoMTIzNCkKd29yZGNsb3VkKHdvcmRzID0gZCR3b3JkLCBmcmVxID0gZCRmcmVxLCBtaW4uZnJlcSA9IDEsc2NhbGU9YygyLDAuNSksCiAgICAgICAgICBtYXgud29yZHM9MTAwLCByYW5kb20ub3JkZXI9RkFMU0UsIHJvdC5wZXI9MC4zNSwgCiAgICAgICAgICBjb2xvcnM9YnJld2VyLnBhbCg4LCAiRGFyazIiKSkKYGBgCgpBbiBpbnRlcmVzdGluZyBxdWVzdGluIHdvdWxkIGJlIGlzIHRoZXJlIHJlbGF0aW9uIGJldHdlZW4gbGVuZ3RoIG9mIHRpdGxlIGFuZCBzb25ncz8gTW9zdCBwcm9iYWJseSBub3csIGJ1dCBsZXQncyBjaGVjayBvdXQuCgpgYGB7cn0KcDggPC0gZ2dwbG90KGx5cmljcywgYWVzKHg9ZmFjdG9yKHRpdGxlX3dvcmRfY291bnQpLCB5PXdvcmRfY291bnQsIGZpbGwgPSBmYWN0b3IodGl0bGVfd29yZF9jb3VudCkpKSArIAogIGdlb21fYm94cGxvdCgpIApwOCAKYGBgCgpgYGB7cn0KY29yKGx5cmljcyR0aXRsZV93b3JkX2NvdW50LCBseXJpY3Mkd29yZF9jb3VudCkKYGBgCiBBcyBleHBlY3RlZCwgdGhlcmUgaXMgbm8gY29ycmVsYXRpbiBiZXR3ZWVuIHRoZXNlIHR3byBxdWFudGl0aXRlcy4KIAo=